package cmd

import (
	lsyslog "github.com/sirupsen/logrus/hooks/syslog"
	"log/syslog"

	log "application/v3/pkg/logger"
	"github.com/jmoiron/sqlx"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc/resolver"

	"application/v3/internal/api"
	"application/v3/internal/backend/networkserver"
	jscodec "application/v3/internal/codec/js"
	"application/v3/internal/config"
	"application/v3/internal/downlink"
	"application/v3/internal/gwping"
	"application/v3/internal/integration"
	"application/v3/internal/migrations/code"
	"application/v3/internal/storage"
)

func setLogLevel() error {
	log.SetLevel(log.Level(uint8(config.C.General.LogLevel)))
	return nil
}

func setSyslog() error {
	if !config.C.General.LogToSyslog {
		return nil
	}

	var prio syslog.Priority

	switch logrus.StandardLogger().Level {
	case logrus.DebugLevel:
		prio = syslog.LOG_USER | syslog.LOG_DEBUG
	case logrus.InfoLevel:
		prio = syslog.LOG_USER | syslog.LOG_INFO
	case logrus.WarnLevel:
		prio = syslog.LOG_USER | syslog.LOG_WARNING
	case logrus.ErrorLevel:
		prio = syslog.LOG_USER | syslog.LOG_ERR
	case logrus.FatalLevel:
		prio = syslog.LOG_USER | syslog.LOG_CRIT
	case logrus.PanicLevel:
		prio = syslog.LOG_USER | syslog.LOG_CRIT
	}

	hook, err := lsyslog.NewSyslogHook("", "", prio, "chirpstack-application-server")
	if err != nil {
		return errors.Wrap(err, "get syslog hook error")
	}

	logrus.AddHook(hook)

	return nil
}

func setGRPCResolver() error {
	resolver.SetDefaultScheme(config.C.General.GRPCDefaultResolverScheme)
	return nil
}

func printStartMessage() error {
	log.WithFields(log.Fields{
		"version": version,
		"docs":    "https://www.chirpstack.io/",
	}).Info("starting ChirpStack Application Server")
	return nil
}

func setupStorage() error {
	if err := storage.Setup(config.C); err != nil {
		return errors.Wrap(err, "setup storage error")
	}
	return nil
}

func setupIntegration() error {
	if err := integration.Setup(config.C); err != nil {
		return errors.Wrap(err, "setup integration error")
	}
	return nil
}

func setupCodec() error {
	if err := jscodec.Setup(config.C); err != nil {
		return errors.Wrap(err, "setup codec error")
	}
	return nil
}

func setupNetworkServer() error {
	if err := networkserver.Setup(config.C); err != nil {
		return errors.Wrap(err, "setup networkserver error")
	}
	return nil
}

func handleDataDownPayloads() error {
	downChan := integration.ForApplicationID(0).DataDownChan()
	go downlink.HandleDataDownPayloads(downChan)
	return nil
}

func migrateGatewayStats() error {
	if err := storage.CodeMigration("migrate_gw_stats", code.MigrateGatewayStats); err != nil {
		return errors.Wrap(err, "migration error")
	}
	return nil
}

func migrateToClusterKeys() error {
	return storage.CodeMigration("migrate_to_cluster_keys", func(db sqlx.Ext) error {
		return code.MigrateToClusterKeys(config.C)
	})
}

func setupAPI() error {
	if err := api.Setup(config.C); err != nil {
		return errors.Wrap(err, "setup api error")
	}
	return nil
}

func startGatewayPing() error {
	go gwping.SendPingLoop()

	return nil
}
